package com.yuanxin.yuanxinkit;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.Log;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.network.OkHttpClientProvider;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.lzy.okgo.OkGo;
import com.lzy.okgo.callback.StringCallback;
import com.lzy.okgo.model.Response;
import com.yanzhenjie.permission.Action;
import com.yanzhenjie.permission.AndPermission;
import com.yanzhenjie.permission.Permission;
import com.sinooceanland.commonutils.DeviceUtil;
import com.yuanxin.yuanxinkit.bean.IMLogin;
import com.yuanxin.yuanxinkit.bean.Login;
import com.yuanxin.yuanxinkit.bean.LoginError;
import com.yuanxin.yuanxinkit.bean.LoginResponseError;
import com.yuanxin.yuanxinkit.utils.TokenInterceptor;

import org.greenrobot.eventbus.EventBus;

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.UUID;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509ExtendedTrustManager;
import javax.net.ssl.X509TrustManager;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;


/**
 * Created by LIYAN on 2016/11/25.
 */

public class AccountModule extends ReactContextBaseJavaModule {

    private static String TAG = AccountModule.class.getSimpleName();
    private String address;
    private String client_id;

    private String access_token;
    private String refresh_token;
    private String token_type;
    private int expires_in;
    private String Login_Url_turing = "/YuanXin.Platform.OAuthService/turing";
    private String Login_Url = "/YuanXin.Platform.OAuthService/token";
    private String Logout_Url = "/YuanXin.Platform.OAuthService/account/logout";

    private SharedPreferences sp;
    private SharedPreferences.Editor edt;

    private ReactApplicationContext reactContext;
    private String sessionid;

    public AccountModule(final ReactApplicationContext reactContext) {
        super(reactContext);
        this.reactContext = reactContext;


        client_id = BuildConfig.AppID;
        address = BuildConfig.LoginAddress;
        Log.e(TAG, "Login_address---" + address + "-Login---client_id---" + client_id);

        sp = reactContext.getSharedPreferences("login", reactContext.MODE_PRIVATE);
        edt = sp.edit();

        //OkHttp底层支持刷新token
        OkHttpClient.Builder builder = OkHttpClientProvider.getOkHttpClient().newBuilder();
        boolean addedInterceptor = false;

        X509TrustManager x509TrustManager = new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {

            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {

            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        };

        SSLContext sslContext = null;
        try {
            sslContext = SSLContext.getInstance("SSL");

            sslContext.init(null, new TrustManager[]{x509TrustManager}, new SecureRandom());

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };

        builder.sslSocketFactory(sslContext.getSocketFactory(), x509TrustManager);
        builder.hostnameVerifier(DO_NOT_VERIFY);

//        for (Interceptor interceptor : builder.interceptors()) {
//            if (interceptor instanceof TokenInterceptor) {
//                addedInterceptor = true;
//                break;
//            }
//        }
//        if (!addedInterceptor) {
//            builder.addInterceptor(new TokenInterceptor(reactContext, this));
//        }
        OkGo.getInstance().setOkHttpClient(builder.build());
//        OkHttpClientProvider.replaceOkHttpClient(OkGo.getInstance().getOkHttpClient());
    }

    @Override
    public String getName() {
        return "AccountManager";
    }

    @ReactMethod
    public void UserLogin(ReadableMap map, final Promise promise) {
        // Log.e(TAG, "UserLogin-map-" + map);


        String username = map.getString("username");
        String password = map.getString("password");
        if (map.hasKey("sessionid")) {
            sessionid = map.getString("sessionid");
        }
        String passwordencrypt = "";
        if (map.hasKey("passwordencrypt"))
            passwordencrypt = map.getString("passwordencrypt");
        String verificationKey = "";
        String verification = "";
        if (map.hasKey("verificationKey"))
            verificationKey = map.getString("verificationKey");
        if (map.hasKey("verification"))
            verification = map.getString("verification");
        boolean isTuring =false;
        if(map.hasKey("isTuring")){
            isTuring = map.getBoolean("isTuring");
        }

        Login(address + (isTuring ? Login_Url_turing : Login_Url), username, password, client_id, DeviceUtil.getDeviceID(reactContext), sessionid, passwordencrypt, verificationKey, verification, promise);

    }

    @ReactMethod
    public void RefreshToken(Promise promise) {

        String refresh_token = sp.getString("refresh_token", null);
        RefreshToken(refresh_token, client_id, promise);
    }

    @ReactMethod
    public void loginOut(Promise promise) {
        String access_token = sp.getString("access_token", null);
        LoginOut("Bearer " + access_token, promise);
    }


    public void Login(String url, String username, String password, String client_id, String deviceId, String sessionid, String passwordencrypt, String verificationKey
            , String verification, final Promise promise) {
        // Log.d(TAG, "登录");
        boolean boo = isNetworkAvailable(reactContext);
        if (!boo) {
            // Log.d(TAG, "没网");
            WritableMap map = Arguments.createMap();
            map.putInt("code", -1);
            map.putString("message", "timeout");
            promise.reject(String.valueOf(-1), String.valueOf(map));
        } else {
            if (sessionid == null || sessionid.equals("")) {
                OkGo.<String>post(url)
                        .headers("Content-Type", "application/x-www-form-urlencoded")
                        .params("grant_type", "password")
                        .params("username", username)
                        .params("password", password)
                        .params("client_id", client_id)
                        .params("deviceId", deviceId)
                        .params("passwordencrypt", passwordencrypt)
                        .params("verificationKey", verificationKey)
                        .params("verification", verification)
                        .execute(new StringCallback() {
                            @Override
                            public void onSuccess(Response<String> response) {
                                if (response == null || response.body() == null || "".equals(response.body())) {
                                    promise.reject("-1", "登录失败");
                                    return;
                                }
                                Gson resgson = new Gson();
                                JsonObject object = resgson.fromJson(response.body(), JsonObject.class);
                                if (object == null) {
                                    WritableMap map = Arguments.createMap();
                                    map.putInt("code", -1);
                                    map.putString("message", "登录失败");
                                    promise.reject(String.valueOf(-1), "登录失败");
                                    return;
                                }
                                if (object.has("access_token")) {
                                    Gson gson = new Gson();
                                    Login login = gson.fromJson(response.body(), Login.class);
                                    access_token = login.getAccess_token();
                                    refresh_token = login.getRefresh_token();
                                    token_type = login.getToken_type();
                                    expires_in = login.getExpires_in();
                                    String expires_time = login.getExpires_time();
                                    String open_id = login.getOpen_id();

                                    edt.putString("access_token", access_token);
                                    edt.putString("refresh_token", refresh_token);
                                    edt.putString("token_type", token_type);
                                    edt.putInt("expires_in", expires_in);
                                    edt.putString("expires_time", expires_time);
                                    edt.putString("open_id", open_id);
                                    edt.apply();

                                    String ImKey_token = "Bearer " + access_token;
                                    ImLogin(ImKey_token, promise);
                                } else if (object.has("error_description")) {
                                    if (object.has("error_description")) {
                                        Gson gson = new Gson();
                                        LoginResponseError loginError = gson.fromJson(response.body(), LoginResponseError.class);
                                        String error = loginError.getError();
                                        String error_description = loginError.getError_description();
                                        WritableMap map = Arguments.createMap();
                                        map.putInt("Code", -1);
                                        map.putString("Domain", error);
                                        map.putString("UserInfo", error_description);
                                        Exception exception = new Exception(String.valueOf(map));
                                        promise.reject(String.valueOf(-1), error_description, exception);
                                    } else {
                                        WritableMap map = Arguments.createMap();
                                        map.putInt("Code", -1);
                                        map.putString("Domain", "invalid_grant");
                                        map.putString("UserInfo", "The user name or password is incorrect");
                                        Exception exception = new Exception(String.valueOf(map));
                                        promise.reject(String.valueOf(-1), "The user name or password is incorrect", exception);
                                    }
                                } else {
                                    Gson gson = new Gson();
                                    LoginError loginError = gson.fromJson(response.body(), LoginError.class);
                                    int errorCode = loginError.getErrorCode();
                                    String errorMsg = loginError.getErrorMsg();
                                    WritableMap map = Arguments.createMap();
                                    map.putInt("code", errorCode);
                                    map.putString("message", errorMsg);
                                    promise.reject(String.valueOf(errorCode), errorMsg);
                                }

                            }

                            @Override
                            public void onError(Response<String> response) {
                                super.onError(response);
                                Log.i(TAG, "onError:" + response.code() + response.getException());
                                promise.reject("400", response.getException());
                            }
                        });
            } else {
                OkGo.<String>post(url)
                        .headers("Content-Type", "application/x-www-form-urlencoded")
                        .params("grant_type", "password")
                        .params("username", username)
                        .params("password", password)
                        .params("client_id", client_id)
                        .params("deviceId", deviceId)
                        .params("sessionid", sessionid)
                        .params("passwordencrypt", passwordencrypt)
                        .params("verificationKey", verificationKey)
                        .params("verification", verification)
                        .execute(new StringCallback() {
                            @Override
                            public void onSuccess(Response<String> response) {
                                if (response == null || response.body() == null || "".equals(response.body())) {
                                    promise.reject("-1", "登录失败");
                                    return;
                                }
                                Gson resgson = new Gson();
                                JsonObject object = resgson.fromJson(response.body(), JsonObject.class);

                                if (object.has("access_token")) {
                                    Gson gson = new Gson();
                                    Login login = gson.fromJson(response.body(), Login.class);
                                    access_token = login.getAccess_token();
                                    refresh_token = login.getRefresh_token();
                                    token_type = login.getToken_type();
                                    expires_in = login.getExpires_in();
                                    String expires_time = login.getExpires_time();
                                    String open_id = login.getOpen_id();
                                    edt.putString("access_token", access_token);
                                    edt.putString("refresh_token", refresh_token);
                                    edt.putString("token_type", token_type);
                                    edt.putInt("expires_in", expires_in);
                                    edt.putString("expires_time", expires_time);
                                    edt.putString("open_id", open_id);
                                    edt.apply();

                                    String ImKey_token = "Bearer " + access_token;
                                    ImLogin(ImKey_token, promise);
                                } else if (object.has("error_description")) {
                                    if (object.has("error_description")) {
                                        Gson gson = new Gson();
                                        LoginResponseError loginError = gson.fromJson(response.body(), LoginResponseError.class);
                                        String error = loginError.getError();
                                        String error_description = loginError.getError_description();
                                        WritableMap map = Arguments.createMap();
                                        map.putInt("Code", -1);
                                        map.putString("Domain", error);
                                        map.putString("UserInfo", error_description);
                                        Exception exception = new Exception(String.valueOf(map));
                                        promise.reject(String.valueOf(-1), error_description, exception);
                                    } else {
                                        WritableMap map = Arguments.createMap();
                                        map.putInt("Code", -1);
                                        map.putString("Domain", "invalid_grant");
                                        map.putString("UserInfo", "The user name or password is incorrect");
                                        Exception exception = new Exception(String.valueOf(map));
                                        promise.reject(String.valueOf(-1), "The user name or password is incorrect", exception);
                                    }
                                } else {
                                    Gson gson = new Gson();
                                    LoginError loginError = gson.fromJson(response.body(), LoginError.class);
                                    int errorCode = loginError.getErrorCode();
                                    String errorMsg = loginError.getErrorMsg();
                                    WritableMap map = Arguments.createMap();
                                    map.putInt("code", errorCode);
                                    map.putString("message", errorMsg);
                                    promise.reject(String.valueOf(errorCode), errorMsg);
                                }
                            }

                            @Override
                            public void onError(Response<String> response) {
                                super.onError(response);
                                Log.i(TAG, "onError:" + response.code() + response.getException());
                                promise.reject("400", response.getException());
                            }
                        });
            }
        }

    }

    public static boolean isNetworkAvailable(Context context) {
        ConnectivityManager connectivity = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivity != null) {
            NetworkInfo info = connectivity.getActiveNetworkInfo();
            if (info != null && info.isConnected()) {
                // 当前网络是连接的
                if (info.getState() == NetworkInfo.State.CONNECTED) {
                    // 当前所连接的网络可用
                    return true;
                }
            }
        }
        return false;
    }

    public void ImLogin(String access_token, final Promise promise) {
        WritableMap map = Arguments.createMap();
        map.putString("access_token", sp.getString("access_token", null));
        map.putString("refresh_token", sp.getString("refresh_token", null));
        map.putString("token_type", sp.getString("token_type", null));
        map.putString("expires_in", sp.getInt("expires_in", 0) + "");
        map.putString("expires_time", sp.getString("expires_time", null));
        map.putString("open_id", sp.getString("open_id", null));
        promise.resolve(map);
    }

    public void RefreshToken(String re_refresh_token, String re_client_id, final Promise promise) {
        OkGo.<String>post(address + Login_Url)
                .headers("Content-Type", "application/x-www-form-urlencoded")
                .params("grant_type", "refresh_token")
                .params("refresh_token", re_refresh_token)
                .params("client_id", re_client_id)
                .execute(new StringCallback() {
                    @Override
                    public void onSuccess(Response<String> response) {
                        if (response == null || response.body() == null || "".equals(response.body())) {
                            promise.reject("-1", "刷新失败");
                            return;
                        }
                        Gson resgson = new Gson();
                        JsonObject object = resgson.fromJson(response.body(), JsonObject.class);
                        if (object.has("access_token")) {
                            Gson gson = new Gson();
                            Login login = gson.fromJson(response.body(), Login.class);
                            access_token = login.getAccess_token();
                            refresh_token = login.getRefresh_token();
                            int expires_in = login.getExpires_in();
                            String expires_time = login.getExpires_time();
                            String open_id = login.getOpen_id();
                            String token_type = login.getToken_type();

                            edt.putString("access_token", access_token);
                            edt.putString("refresh_token", refresh_token);
                            edt.putString("token_type", token_type);
                            edt.putInt("expires_in", expires_in);
                            edt.putString("expires_time", expires_time);
                            edt.putString("open_id", open_id);
                            edt.apply();

                            String ImKey_token = "Bearer " + access_token;
                            ImLogin(ImKey_token, promise);
                        } else {
                            if (object.has("error_description")) {
                                Gson gson = new Gson();
                                LoginResponseError loginError = gson.fromJson(response.body(), LoginResponseError.class);
                                String error = loginError.getError();
                                String error_description = loginError.getError_description();
                                WritableMap map = Arguments.createMap();
                                map.putInt("Code", -1);
                                map.putString("Domain", error);
                                map.putString("UserInfo", error_description);
                                Exception exception = new Exception(String.valueOf(map));
                                promise.reject(String.valueOf(-1), error_description, exception);
                            } else {
                                WritableMap map = Arguments.createMap();
                                map.putInt("Code", -1);
                                map.putString("Domain", "invalid_grant");
                                map.putString("UserInfo", "The user name or password is incorrect");
                                Exception exception = new Exception(String.valueOf(map));
                                promise.reject(String.valueOf(-1), "The user name or password is incorrect", exception);
                            }
                        }
                    }

                    /**
                     * 请求失败，响应错误，数据解析错误等，都会回调该方法， UI线程
                     *
                     * @param response
                     */
                    @Override
                    public void onError(Response<String> response) {
                        super.onError(response);
                        //token刷新失败前端会跳转到登录，所以需要登出IM及解绑PUSH
                        EventBus.getDefault().post("imLogout");
                        promise.reject(response.getException());
                    }
                });
    }

    public void LoginOut(String Bearer_token, final Promise promise) {
        OkGo.<String>post(address + Logout_Url)
                .headers("Content-Type", "application/x-www-form-urlencoded")
                .headers("Authorization", Bearer_token)
                .execute(new StringCallback() {
                    @Override
                    public void onSuccess(Response<String> response) {
                        // Log.e(TAG, "LoginOut-onSuccess-" + response + "-s-" + response.body());
                        EventBus.getDefault().post("imLogout");
                        //清除本地缓存
                        edt.clear();
                        edt.commit();
                        promise.resolve(true);

                    }
                });
    }

    public void LoginOutSync(String Bearer_token) {
        OkGo.<String>post(address + Logout_Url)
                .headers("Content-Type", "application/x-www-form-urlencoded")
                .headers("Authorization", Bearer_token)
                .execute(new StringCallback() {
                    @Override
                    public void onSuccess(Response<String> response) {
                        // Log.e(TAG, "LoginOut-onSuccess-" + response + "-s-" + response.body());
                        EventBus.getDefault().post("imLogout");
                    }
                });
    }


    /**
     * 同步请求方式，获取最新的Token
     *
     * @return
     */

    public String RefreshTokenSync() {
        SharedPreferences sp = reactContext.getSharedPreferences("login", reactContext.MODE_PRIVATE);
        SharedPreferences.Editor edt = sp.edit();
        String refresh_token = sp.getString("refresh_token", null);

        String token = null;
        try {
            okhttp3.Response response = OkGo.post(address + Login_Url)
                    .headers("Content-Type", "application/json")
                    .params("grant_type", "refresh_token")
                    .params("refresh_token", refresh_token)
                    .params("client_id", client_id)
                    .execute();

            String s = response.body().string();
            Gson resgson = new Gson();
            JsonObject object = resgson.fromJson(s, JsonObject.class);

            if (object.has("access_token")) {
                Gson gson = new Gson();
                Login login = gson.fromJson(s, Login.class);
                token = login.getAccess_token();
                refresh_token = login.getRefresh_token();
                int expires_in = login.getExpires_in();
                String expires_time = login.getExpires_time();
                String open_id = login.getOpen_id();
                String token_type = login.getToken_type();

                edt.putString("access_token", token);
                edt.putString("refresh_token", refresh_token);
                edt.putString("token_type", token_type);
                edt.putInt("expires_in", expires_in);
                edt.putString("expires_time", expires_time);
                edt.putString("open_id", open_id);
                edt.apply();

//                String url = "/OAuthServices/account/imKey";
//                String ImKey_token = "Bearer " + token;
//                ImLoginSync(address + url, ImKey_token);
            } else {
                // Log.e(TAG, response.body().toString());
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            return token;
        }
    }

    public void ImLoginSync(String url, String access_token) {
        try {
            SharedPreferences sp = reactContext.getSharedPreferences("login", reactContext.MODE_PRIVATE);
            SharedPreferences.Editor edt = sp.edit();
            okhttp3.Response response = OkGo.post(url)
                    .headers("Content-Type", "application/x-www-form-urlencoded")
                    .params("Authorization", access_token)
                    .execute();
            String s = response.body().string();
            Gson resgson = new Gson();
            JsonObject object = resgson.fromJson(s, JsonObject.class);

            if (object.has("imConnectionId")) {
                Gson imgson = new Gson();
                IMLogin imLogin = imgson.fromJson(s, IMLogin.class);
                String imConnectionId = imLogin.getImConnectionId();
                int userId = imLogin.getUserId();
                String uuid = imLogin.getUuid();
                String userName = imLogin.getUserName();
                String photo = imLogin.getPhoto();
                edt.putString("IM_Token", imConnectionId);
                edt.putInt("IM_UserId", userId);
                edt.putString("IM_UUID", uuid);
                edt.putString("IM_UserName", userName);
                edt.putString("IM_Photo", photo);
                edt.apply();

                String refresh_token = sp.getString("refresh_token", null);
                String token_type = sp.getString("token_type", null);
                int expires_in = sp.getInt("expires_in", 0);
                String expires_time = sp.getString("expires_time", null);
                String open_id = sp.getString("open_id", null);
                WritableMap map = Arguments.createMap();
                map.putString("access_token", access_token);
                map.putString("refresh_token", refresh_token);
                map.putString("token_type", token_type);
                map.putString("expires_in", expires_in + "");
                map.putString("expires_time", expires_time);
                map.putString("open_id", open_id);

                EventBus.getDefault().post("imLogin");
            } else {
                // Log.e(TAG, response.body().toString());
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
